import React, { useEffect } from "react";

type name = {
  name: number;
  age: string;
  getname: void;
  setname: number;
  [key: string]: any;
};

type keyofname = keyof name;

export default (): JSX.Element => {
  const objectTest = () => {
    let obj: name = {
      name: 1,
      age: "c",
      ge: undefined,
      get getname() {
        // 更有利于后台工作，写法也比较简洁
        console.log("getter");
        return name;
      },
      set setname(str: number) {
        // 更有利于后台工作，写法也比较简洁
        console.log("setter");
        this.name = str;
      },
    };
    Object.values(obj).map((item) => console.log(item)); // 遍历每个值
    Object.keys(obj).map((item) => console.log(item)); // 遍历属性名
    Object.entries(obj).map((item) => console.log(item)); // 遍历返回数组【属性名, 属性值】
    console.log(Object.fromEntries(Object.entries(obj))); // 将Object.entries的数组重新转成对象
    let x: keyofname;
    for (x in obj) {
      // 循环遍历对象
      console.log(x, obj[x]);
    }
    console.log(obj.getname);
    console.log((obj.setname = 10));
    console.log(obj);
    console.log(Object.create(obj)); // 浅拷贝 obj基础上创建新对象
    console.log(Object.defineProperty(obj, "age", { value: "b" })); // 添加或更改对象属性
    console.log(
      Object.defineProperties(obj, {
        // 添加或更改对象属性
        property1: {
          value: true, // 属性值
          writable: true, // 属性值可更改
          enumerable: true, // 属性可枚举
          configurable: true, // 属性可重新配置
        },
        age: {
          value: "Hello",
          writable: true,
        },
        // etc. etc.
      })
    );
    console.log(Object.assign(obj, {})); // 合并对象浅拷贝
    console.log(obj.hasOwnProperty("ge")); // 判断是否存在某个属性即使属性的值是null或undefined
    console.log(Object.getOwnPropertyDescriptor(obj, "age")); // 返回对象上某个属性的属性描述
    console.log(Object.getOwnPropertyNames(obj)); // 以数组的形式返回属性名
    console.log(Object.getPrototypeOf(obj)); // 访问原型链 === __proto__

    // ---------------------保护对象（对象的__proto__都是可以修改的）---------------------

    // Object.preventExtensions(obj); // 设置不添加属性，可以通过Object.defineProperty修改但是不能直接obj.age修改
    // Object.defineProperty(obj, "age", { value: "b" }) // 原来可以就可以
    // obj.age = '100' // 原来可以就可以
    // delete obj.ge // 可以
    // obj.a = 10; // 不可以

    console.log(Object.isExtensible(obj)); // 判断是否可以添加对象，对应Object.preventExtensions

    // Object.seal(obj); // 防止任何更改属性（不是值）
    // Object.defineProperty(obj, "age", { value: "b" }); // 原来可以就可以
    // obj.age = '100' // 原来可以就可以
    // delete obj.age // 不可以
    // obj.a = 10 // 不可以

    console.log(Object.isSealed(obj)); // 对象是否被密封对应Object.seal

    // Object.freeze(obj); // 防止对对象进行任何更改
    // Object.defineProperty(obj, "age", { value: "b" }); // 不可以
    // obj.age = '100' // 不可以
    // obj.a = 10 // 不可以

    console.log(Object.isFrozen(obj)); // 对象是否被冻结对应Object.freeze
  };

  const Mapfn /* 字典 */ = () => {
    // Map 对象存有键值对，其中的键可以是任何数据类型。
    // Map 对象记得键的原始插入顺序。
    // Map 对象具有表示映射大小的属性。
    let addItem = { a: "10" };
    const newMap = new Map<any, any>([
      ["a", 1],
      ["a", 2], // 即使有两个a最终的结果只会保留一个
      ["b", () => console.log("done")],
    ]);
    // const newMap = new Map()
    console.log(newMap);
    console.log(newMap.size); // 字典个数长度
    newMap.set(addItem, 501); // 设置对应的键值对，如果是引用类型的键需要新开辟一块内存否则get不到
    newMap.set("age", 501);
    newMap.set("age", 502); // 即使set两次也只会有一个
    console.log(newMap);
    console.log(newMap.get(addItem), newMap.get("a")); // 根据键获取值
    const entriesMap = newMap.entries(); // 获取键值对（有点类似链表）
    console.log(
      Object.fromEntries(entriesMap), // 和下面的next会相互影响转换后就没有next了
      entriesMap.next().value, // next后就没有entriesMap了
      entriesMap.return,
      entriesMap.next().value,
      Object.fromEntries(entriesMap)
    ); // return什么都不做返回undefined但是不会跳过，next去找下一个键值对
    const valuesMap = newMap.values(); // 获取值
    console.log(valuesMap.next().value, valuesMap.next().value); // 同上
    const keysMap = newMap.keys(); // 获取值
    console.log(keysMap.next().value, keysMap.next().value); // 同上
    // newMap.clear() // 清空map字典
    // newMap.delete(addItem) // 删除由键指定的元素。
    // newMap.forEach(item => console.log(item)) // 遍历item对应的值
    // console.log(newMap.has(addItem)) // 查看是否存在否个值
    // console.log(newMap)
  };

  const Setfn /* 集合 */ = () => {
    // Set 是唯一值的集合。
    // 每个值在 Set 中只能出现一次。
    // 一个 Set 可以容纳任何数据类型的任何值。
    const newSet = new Set(["a", "b", "c"]);
    console.log(newSet, newSet.size); // 集合个数长度
    newSet.add("d");
    // newSet.delete('d') // 删除集合中的某个
    // newSet.clear() // 清空集合
    console.log(newSet, newSet.has("b")); // 是否存在b
    const keysMap = newSet.keys();
    console.log(keysMap.next().value, keysMap.return, keysMap.next().value); // return什么都不做返回undefined但是不会跳过，next去找下一个
    const valuesMap = newSet.values();
    console.log(valuesMap.next().value, valuesMap.next().value);
    newSet.forEach((item) => console.log(item)); // 遍历
    const entriesSet = newSet.entries(); // 转变为键值对形式
    console.log(
      Array.from(newSet), // 转为数组
      Array.from(entriesSet) // 转为二维数组
    );
    console.log(
      Object.fromEntries(entriesSet), // 和下面的next会相互影响转换后就没有next了
      entriesSet.next().value, // next后就没有entriesSet了
      entriesSet.next().value,
      Object.fromEntries(entriesSet)
    ); // 转化成键值对后转成对象
  };
  
  useEffect(() => {
    // objectTest()
    // Mapfn()
    Setfn();
  }, []);

  return <div>object</div>;
};
